/*
 * Robot11API.cpp
 *
 *  Created on: 17/11/2013
 *      Author: gonzalo
 */

#include "Robot11API.h"

Robot11API::Robot11API(AdminKeys adminKeys) :
comRobot11(adminKeys.getRobot11Key()),
comRobot12(adminKeys.getRobot12Key()),
comAgv(adminKeys.getAgvKey()),
comCanastos(adminKeys.getCanastosKey()),
comCinta(adminKeys.getCintaKey())
{
}

Producto Robot11API::obtenerProducto() {
	Producto prod;
	prod.productoId = 0;
	while (prod.productoId == 0) {
		CLogger::log("Inspeccionar cinta.", LogLevelEnum::INFO);
		comCinta.lockCinta();
		if(comCinta.cintaVacia()) {
			CLogger::log("Cinta vacía, espero.", LogLevelEnum::INFO);
			comCinta.unlockCinta();
			comRobot11.esperarCinta();
			CLogger::log("Hay algo en la cinta.", LogLevelEnum::INFO);
			comCinta.lockCinta();
		}
		if(!comCinta.ultimoEspacioVacio()) {
			comCinta.unlockCinta();
			CLogger::log("Obtengo producto.", LogLevelEnum::INFO);
			prod = comCinta.obtenerProducto();
			if (!comCinta.primerEspacioVacio()) {
				CLogger::log("Como el primer espacio está vacío le aviso al R5.", LogLevelEnum::INFO);
				PedidoCintas pedido;
				pedido.a = 0;
				pedido.id = (comCinta.getKey() == 'i')? 1 : 2;
				comRobot5.enviarAvisoDeCintaAR5(pedido);
			}
		}
		CLogger::log("Muevo cinta.", LogLevelEnum::INFO);
		comCinta.moverCinta();
		CLogger::log("Devuelvo cinta.", LogLevelEnum::INFO);
		comCinta.unlockCinta();
	}

	CLogger::log("Producto para procesar: " + StringUtils::itos(prod.productoId), LogLevelEnum::INFO);
	CLogger::log("Despierto robot 12.");
	comRobot12.despertarHayProductoCinta();
	return prod;
}

void Robot11API::procesarProducto(Producto prod) {
	CLogger::log("Procesar producto " + StringUtils::itos(prod.productoId), LogLevelEnum::INFO);
	std::map<TipoPieza, int> piezasCantidad = MapaPiezasProducto::obtenerPiezasYCantidad(prod.tipo);
	std::map<TipoPieza, int>::iterator it;
	for (it = piezasCantidad.begin(); it != piezasCantidad.end(); it++) {
		TipoPieza pieza = (*it).first;
		int cantidad = (*it).second;
		CLogger::log("Colocando la pieza " + StringUtils::itos(pieza) + "("+StringUtils::itos(cantidad)+")", LogLevelEnum::INFO);
		comCanastos.marcarUso(pieza);
		Random::msleep(500, 800);

		if (comCanastos.getEstadoCanasto(pieza).ausente){
			comAgv.agregarPedidoCanastos(this->buildPedidoPiezas(pieza));
			comCanastos.agregarEsperaDePieza(pieza);
			CLogger::log("Falta el canasto " + StringUtils::itos(pieza) + ", esperando al AGV.", LogLevelEnum::INFO);
			comRobot11.esperarPieza();
		}
		int restante = cantidad;
		/* Si no me alcanzan las piezas se las pido al AGV */
		while ((restante = comCanastos.usarCantidad(pieza, abs(restante))) < 0) {
			comAgv.agregarPedidoCanastos(this->buildPedidoPiezas(pieza));
			comCanastos.agregarEsperaDePieza(pieza);
			CLogger::log("Faltan piezas del canasto "+StringUtils::itos(pieza)+", esperando al AGV.", LogLevelEnum::INFO);
			comRobot11.esperarPieza();
		}

		comCanastos.desmarcarUso(pieza);
	}
	CLogger::log("Termina de procesar producto " + StringUtils::itos(prod.productoId) + " y espera al robot 12.", LogLevelEnum::INFO);
	if (!comRobot12.estaListo()) {
		comRobot11.esperarRobot12();
		CLogger::log("Robot 12 listo, producto " + StringUtils::itos(prod.productoId) + " listo para avanzar.", LogLevelEnum::INFO);
	}
}

void Robot11API::avanzarProductoDeCintaA(Producto prod) {
	CLogger::log("Avanzar producto cinta A " + StringUtils::itos(prod.productoId), LogLevelEnum::INFO);
	avanzarProductoCintaA(prod);
	CLogger::log("Avance Ok");
}

void Robot11API::avanzarProductoDeCintaB(Producto prod) {
	CLogger::log("Avanzar producto cinta B" + StringUtils::itos(prod.productoId), LogLevelEnum::INFO);
	avanzarProductoCintaB(prod);
	CLogger::log("Avance Ok");
}

void Robot11API::avanzarProducto(Producto prod) {
	if (this->comRobot11.getKey() == 'i') {
		this->avanzarProductoDeCintaA(prod);
	} else {
		this->avanzarProductoDeCintaB(prod);
	}
}

PedidoPiezas Robot11API::buildPedidoPiezas(TipoPieza pieza){
	PedidoPiezas pedido;
	memset((void*)pedido.piezas, 0, MAX_PIEZAS * sizeof(int));
	pedido.piezas[0] = pieza;
	return pedido;
}

Robot11API::~Robot11API() {
}
